#ifndef __INTER_MAIN_H__
#define __INTER_MAIN_H__

//types of the trace records
#define MAX_TYPES		20
#define MAX_TOKEN_LEN	100

/*
 * The following enumation defines the types of the trace records found in rec.txt.
 */
enum{
	TRACE_REC_SCHED=0,
	TRACE_REC_WAKE,
	TRACE_REC_YIELD,
	TRACE_REC_BLOCK,
	TRACE_REC_OFFLINE,
	TRACE_REC_SCHED_OUT,
	TRACE_REC_LOST_RECORDS
}trace_records;

/*
 * The folowing enumation defines the status of intermediate time slices.
 */
enum{
	INTER_TIME_SLICE_BEGIN_HALF = 100,
	INTER_TIME_SLICE_END_HALF
} inter_time_slice_types;
	

/*
 * Notes: If you want to add new type of records, you should define the specific routine used to process this new type of record, and change the global variable defined in inter_main.c, which is named type_array[], correspondently.
 */

struct rec_types{
	char token_name[MAX_TOKEN_LEN];
	int	type;
	void (*func)();
	int count;
};

/*
 * PCPU data structure
 */
#define MAX_PCPU	255
struct pcpu{
	struct list_head pcpu_list_elem;
	struct list_head inter_time_slice_list;
	unsigned int pcpu_id;
	unsigned long long max_tsc;
	unsigned long long min_tsc;
};

/*
 * structure to store domain_wake record
 */
struct wake_event{
	struct list_head wake_event_list_elem;
	unsigned long long wake_tsc;
	unsigned domain_id, vcpu_id;
	unsigned pcpu_id;
};

/*
 * structure to store do_yield records
 */
struct yield_event{
	struct list_head yield_event_list_elem;
	unsigned long long yield_tsc;
	unsigned domain_id, vcpu_id;
	unsigned pcpu_id;
};

/*
 * intermediate time slice records. The idea is to generate one or two intermediate time
 * slice records when processing each line within the trace record. 
 */
struct inter_time_slice{
	struct list_head inter_time_slice_elem;
    unsigned long long sched_in_tsc;
    unsigned long long sched_out_tsc;

	int pcpu_id;

	int inter_time_slice_status;
    int sched_in_type;  //identify how the VCPU was scheduled in.
    union{
        struct wake_data_t wake_data;
    }sched_in;

    int sched_out_type; //identify how the VCPU was scheduled out.
    union{
        struct yield_data_t yield_data;
    }sched_out;

	unsigned domain_id, vcpu_id;
};

/*
 * predeclarations of functions.
 */
void inter_init( void );
void inter_exit( void );
int inter_working( void );

struct pcpu* inter_update_pcpu_list( void );
void browse_pcpu_list( void );
void reclaim_pcpu_list( void );

struct inter_time_slice* find_inter_time_slice_by_id( struct pcpu*ppcpu, unsigned domain_id, unsigned vcpu_id );
void browse_inter_time_slice_records( struct pcpu *ppcpu );
int create_time_slice_and_add( struct inter_time_slice* pinter_time_slice );
void final_assemble_inter_time_slice( void );
struct wake_event* find_wake_event( struct inter_time_slice* pinter_time_slice );
void annotate_wake_events( void );
int annotate_one_wake_event( struct wake_event *pwake_event );
void reclaim_wake_event_list( void );

void annotate_yield_events( void );
int annotate_one_yield_event( struct yield_event *pyield_event );
void reclaim_yield_event_list( void );

//	specific record processing
void handle_enter_scheduler( int rec_type, struct pcpu* );
void handle_domain_wake( int rec_type, struct pcpu* );
void handle_do_yield( int rec_type, struct pcpu* ppcpu );
void handle_running_to_blocked( int rec_type, struct pcpu* );
void handle_running_to_runnable( int rec_type, struct pcpu* );
void handle_lost_records( int rec_type, struct pcpu* );

#endif

